package cn.tedu.charging.order.quartz;

import cn.tedu.charging.order.dao.mapper.OrderFailMapper;
import cn.tedu.charging.order.dao.mapper.OrderSuccessMapper;
import cn.tedu.charging.order.pojo.po.ChargingOrderFailPO;
import cn.tedu.charging.order.pojo.po.ChargingOrderSuccessPO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;

import java.util.Date;

/**
 * 设备检查任务
 * 用来发现 检查设备无响应
 * Job要用 org.quartz
 * 设备   检查   工作
 * Device Check Job
 */
//DeviceCheckJob这个任务是什么时候创建呢？
    //DeviceCheckJob 不能在容器中 ，因为不同的订单创建的时间是不同的（在订单服务启动的时候创建任务了）
    //因为以下的任务是根据订单创建的（每个订单一个任务）（应该在创建订单的时候创建任务）
@Slf4j
public class DeviceCheckJob implements Job {

    /**
     * 必须有一个无参数的构造器
     *  如果没有， 在初始化 new DeviceCheckJob 调用 Class newInstance 实例化，
     *  通过无参的构造器实例化对象
     *  getConstructor0() 获取无参构造器
     *  public DeviceCheckJob(String orderNo) 覆盖 默认的无参构造器
     *  找不到方法 抛异常 NoSuchMethodException  找不到构造器，创建不了 DeviceCheckJob对象
     */
    public DeviceCheckJob(){

    }
    public DeviceCheckJob(String orderNo) throws SchedulerException {
        log.debug("创建定时任务");

        //创建调度器工厂 （生产调度器的工厂）
        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        //获取调度器
        Scheduler scheduler = schedulerFactory.getScheduler();

        //当前时间加1分钟
        //获取当前时间
        long now = System.currentTimeMillis();
        //任务执行的时间 设置为 当前时间的1分钟之后
        long deviceCheckTime = now + 60 * 1000;
        //把时间戳 转换成 java.util.Date对象
        Date triggerTime = new Date(deviceCheckTime);
        //触发器，在什么时候触发 在startAt(triggerTime)这里触发

       //这是定时 //定义触发器 任务一分钟之后执行
        Trigger trigger =
                TriggerBuilder.newTrigger().startAt(triggerTime).build();
       //这是任务（任务详情）  就是创建任务的时候把orderNo给塞进去
        JobDetail jobDetail = JobBuilder.newJob(DeviceCheckJob.class)
                        //给任务起名字
                        //deviceCheckJob设备检查 ,deviceCheckJob设备检查的分组
                        //名字和组的目的是什么？ 来区分不同的任务
                        //不同的用户创建不同的订单是同一个任务吗？不是吧 为了区分可以加一个时间，或者随机号或者订单号
                        .withIdentity("deviceCheckJob" + orderNo , "deviceCheckJobGroup")
                        //这是任务（任务详情）  就是创建任务的时候把orderNo给塞进去
                        .usingJobData("orderNo",orderNo)
                        .build();
        //该用调度器了
        //调度器 把任务和触发器进行绑定
        //调度器 scheduler，让任务JobDetail 和按照 触发器的时间trigger 来触发
        scheduler.scheduleJob(jobDetail,trigger);
        //启动调度器
        scheduler.start();
    }

    /**
     * 任务执行的逻辑 具体的任务
     * 7. 判断是否有订单记录
     * 8. 有成功订单记录 订单状态是 充电中 说明设备 有响应，设备收到了指令后，正常的返回开始充电成功的响应，保存成功订单记录  无需处理
     * 9. 没有成功订单记录
     * 10. 判断是否有失败订单记录
     * 11. 有失败订单记录   失败原因 有响应-无法充电  无需处理
     * 12. 没有失败订单记录
     * 13. 插入失败订单记录 失败原因 设备无响应 通知用户和维修人员 设置枪状态为 故障
     * @param jobExecutionContext
     * @throws JobExecutionException
     *
     * 任务执行的时候得判断订单记录，订单记录怎么判断呢？要通过订单号现在方法只有JobExecutionContext jobExecutionContext
     * 这一个入参
     */
    //execute这是一个执行的方法   执行的时候得判断订单 入参是JobExecutionContext Context

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
              log.debug("任务开始执行");
       //要获取订单号才能执行execute这个方法
       //订单号怎么传给它呢？
       //执行的时候 从上面的创建任务的代码中从jobDetail取出来
      JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
       String orderNo = jobDataMap.getString("orderNo");
      log.debug("任务获取订单号:{}",orderNo);
      log.debug("查询成功订单记录：订单号{}",orderNo);

      //SpringContextUtils.getBean("具体的mapper")
        //取出   成功的mapper
        OrderSuccessMapper orderSuccessMapper = SpringContextUtils.getBean(OrderSuccessMapper.class);
        //可以用mybatis-pilu的API了  传的是订单id 而不是id
        //id 就用selectById API   selectCount是查询有几条   selectBatchIds 就是批量的id  selectList 返回多条记录 selectMapsPage是分页的
        //selectObjs 是返回列表的
        //所以要用selectOne  其中入参是queryWrapper 查询包裹，包一些东西进去
        QueryWrapper queryWrapper = new QueryWrapper<>();
        //column:表中的列的名字  值
        queryWrapper.eq("bill_id",orderNo);
        //这样就能查询出订单记录来了
        ChargingOrderSuccessPO chargingOrderSuccessPO = orderSuccessMapper.selectOne(queryWrapper);
        log.debug("查询成功订单记录：订单号{}，查询结果{}",orderNo,chargingOrderSuccessPO);
        //判定是否有成功订单记录
        if(chargingOrderSuccessPO == null) {
            //没有成功订单记录
            log.debug("没有成功订单记录，查询是否有失败订单记录",orderNo);
            log.debug("查询失败订单记录:订单号{}",orderNo);

            OrderFailMapper orderFailMapper =
                    SpringContextUtils.getBean(OrderFailMapper.class);
            QueryWrapper  failOrderqueryWrapper= new QueryWrapper<>();
            failOrderqueryWrapper.eq("bill_id",orderNo);
            ChargingOrderFailPO chargingOrderFailPO = orderFailMapper.selectOne(failOrderqueryWrapper);
            log.debug("查询失败订单记录:订单号{}，查询结果{}",orderNo,chargingOrderFailPO);
            //判断是否有失败订单记录
            if(chargingOrderFailPO == null) {
                log.debug("没有失败订单记录，保存失败记录，失败原因为<<设备无响应>>");
                ChargingOrderFailPO failPO = new ChargingOrderFailPO();
                failPO.setBillId(orderNo);
                failPO.setFailDesc("设备故障-无响应");

            }


        }

    }

    //   @Override
//    public void execute(JobExecutionContext context) throws JobExecutionException {
//        log.debug("任务开始执行");
//        //要获取订单号才能执行execute这个方法
//        //订单号怎么传给它呢？
//        //执行的时候 从上面的创建任务的代码中从jobDetail取出来
//        JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
//        String orderNo = jobDataMap.getString("orderNo");
//        log.debug("任务获取订单号:{}",orderNo);
//
//    }
}
